﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using Noris.Tools.FrxEditor.Data;

namespace Noris.Tools.FrxEditor.Components
{
    /// <summary>
    /// Status bar s progresem a s asynchronním přístupem k datům
    /// </summary>
    public class StatusBarProgress : StatusStrip
    {
        #region Konstrukce
		/// <summary>
		/// Status bar s progresem a s asynchronním přístupem k datům. Konstruktor.
		/// </summary>
        public StatusBarProgress()
        {
            this.Init();
        }
		/// <summary>
		/// Inicializace prvku
		/// </summary>
        protected void Init()
        {
            this._MainText = new System.Windows.Forms.ToolStripStatusLabel();
            this._ProgressCaption = new System.Windows.Forms.ToolStripStatusLabel();
            this._ProgressBar = new System.Windows.Forms.ToolStripProgressBar();
            this._ProgressCount = new System.Windows.Forms.ToolStripStatusLabel();
            this._ProgressError = new System.Windows.Forms.ToolStripStatusLabel();

            this.SuspendLayout();

            this.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this._MainText, this._ProgressCaption, this._ProgressBar, this._ProgressCount, this._ProgressError });

            this.Size = new System.Drawing.Size(966, 24);
            this.Dock = DockStyle.Bottom;

            this._MainText.AutoSize = false;
            this._MainText.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.None;
            this._MainText.Name = "_StatusInfo";
            this._MainText.Size = new System.Drawing.Size(462, 19);
            this._MainText.Text = "Status";
            this._MainText.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;

            this._ProgressCaption.AutoSize = false;
            this._ProgressCaption.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
            this._ProgressCaption.Name = "_StatusCaption";
            this._ProgressCaption.Size = new System.Drawing.Size(110, 19);
            this._ProgressCaption.Text = "";
            this._ProgressCaption.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
            this._ProgressCaption.Visible = false;

            this._ProgressBar.Name = "_StatusProgress";
            this._ProgressBar.Size = new System.Drawing.Size(250, 18);
            this._ProgressBar.Minimum = 0;
            this._ProgressBar.Maximum = 1000;
            this._ProgressBar.Value = 0;
            this._ProgressBar.Visible = false;

            this._ProgressCount.AutoSize = false;
            this._ProgressCount.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Right;
            this._ProgressCount.Name = "_StatusCount";
            this._ProgressCount.Size = new System.Drawing.Size(80, 19);
            this._ProgressCount.Text = "";
            this._ProgressCount.Visible = false;

            this._ProgressError.AutoSize = false;
            this._ProgressError.Name = "_StatusErrors";
            this._ProgressError.Size = new System.Drawing.Size(95, 19);
            this._ProgressError.Text = "";
            this._ProgressError.Visible = false;

            this.ResumeLayout(false);
        }
        private System.Windows.Forms.ToolStripStatusLabel _MainText;
        private System.Windows.Forms.ToolStripStatusLabel _ProgressCaption;
        private System.Windows.Forms.ToolStripProgressBar _ProgressBar;
        private System.Windows.Forms.ToolStripStatusLabel _ProgressCount;
        private System.Windows.Forms.ToolStripStatusLabel _ProgressError;
        #endregion
        #region Property - čtení a nastavování dat, je možno provádět asynchronně (z cizího threadu)
        /// <summary>
        /// Hlavní text toolbaru
        /// </summary>
        public string MainText
        {
            get { return GetData().MainText; }
            set { SetData(new StatusData() { MainText = value }); }
        }
        /// <summary>
        /// Tooltip na hlavním textu toolbaru
        /// </summary>
        public string MainTextTooltip
        {
            get { return GetData().MainTextTooltip; }
            set { SetData(new StatusData() { MainTextTooltip = value }); }
        }
        /// <summary>
        /// Příznak viditelnosti textu před progress barem
        /// </summary>
        public bool ProgressCaptionVisible
        {
            get { return GetData().ProgressCaptionVisible.Value; }
            set { SetData(new StatusData() { ProgressCaptionVisible = value }); }
        }
        /// <summary>
        /// Aktuální text uvedený před progress barem.
        /// Vložení textu současně nastavuje Visible (text == null ?  Visible = false.
        /// </summary>
        public string ProgressCaptionText
        {
            get { return GetData().ProgressCaptionText; }
            set { SetData(new StatusData() { ProgressCaptionText = (value == null ? "" : value), ProgressCaptionVisible = (value != null) }); }
        }
        /// <summary>
        /// Příznak viditelnosti progress baru (fyzický ukazatel postupu)
        /// </summary>
        public bool ProgressBarVisible
        {
            get { return GetData().ProgressBarVisible.Value; }
            set { SetData(new StatusData() { ProgressBarVisible = value }); }
        }
        /// <summary>
        /// Aktuální hodnota progress baru v rozsahu { 0 ÷ 1 } (fyzický ukazatel postupu)
        /// </summary>
        public float ProgressBarRatio
        {
            get { return GetData().ProgressBarRatio.Value; }
            set { SetData(new StatusData() { ProgressBarRatio = value }); }
        }
        /// <summary>
        /// Příznak viditelnosti textu za progress barem (typicky počet zpracovávání)
        /// </summary>
        public bool ProgressCountVisible
        {
            get { return GetData().ProgressCountVisible.Value; }
            set { SetData(new StatusData() { ProgressCountVisible = value }); }
        }
        /// <summary>
        /// Aktuální text uvedený za progress barem (typicky počet zpracovávání)
        /// Vložení textu současně nastavuje Visible (text == null ?  Visible = false.
        /// </summary>
        public string ProgressCountText
        {
            get { return GetData().ProgressCountText; }
            set { SetData(new StatusData() { ProgressCountText = (value == null ? "" : value), ProgressCountVisible = (value != null) }); }
        }
        /// <summary>
        /// Příznak viditelnosti textu za Count (typicky počet chyb)
        /// </summary>
        public bool ProgressErrorVisible
        {
            get { return GetData().ProgressErrorVisible.Value; }
            set { SetData(new StatusData() { ProgressErrorVisible = value }); }
        }
        /// <summary>
        /// Aktuální text uvedený před progress barem.
        /// Vložení textu současně nastavuje Visible (text == null ?  Visible = false.
        /// </summary>
        public string ProgressErrorText
        {
            get { return GetData().ProgressErrorText; }
            set { SetData(new StatusData() { ProgressErrorText = (value == null ? "" : value), ProgressErrorVisible = (value != null) }); }
        }
		/// <summary>
		/// Zobrazí všechny prvky zobrazující Progress
		/// </summary>
        public void ProgressShowAll()
        {
            this.ProgressShow(true, true, true, true);
        }
		/// <summary>
		/// Skryje všechny prvky zobrazující Progress
		/// </summary>
        public void ProgressHide()
        {
            this.ProgressShow(false, false, false, false);
        }
		/// <summary>
		/// Zobrazí požadované prvky zobrazující Progress
		/// </summary>
		/// <param name="showCaption"></param>
		/// <param name="showProgressBar"></param>
		/// <param name="showCount"></param>
		/// <param name="showError"></param>
        public void ProgressShow(bool showCaption, bool showProgressBar, bool showCount, bool showError)
        {
            StatusData data = new StatusData() { ProgressCaptionVisible = showCaption, ProgressBarVisible = showProgressBar, ProgressCountVisible = showCount, ProgressErrorVisible = showError };
            this.SetData(data);
        }
        /// <summary>
        /// Kompletní data status baru (Main text, progress, další položky).
        /// Tuto property je možno používat z různých Threadů.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public StatusData CurrentStatusData
        {
            get { return GetData(); }
            set { SetData(value); }
        }
        /// <summary>
        /// Metoda pro vložení dat do status baru.
        /// Metodu lze předat jako delegáta do výkonných metod, které hlásí progress.
        /// Metodu lze volat z libovolného threadu, případnou invokaci threadu vlastníka provede interně.
        /// </summary>
        /// <param name="data"></param>
        public void SetStatusBarData(StatusData data)
        {
            this.SetData(data);
        }
        #endregion
        #region Privátní metody pro přístup k datům
		/// <summary>
		/// Vrátí datový objekt, který popisuje obsah status baru.
		/// Zvládá asynchronní přístup.
		/// </summary>
		/// <returns></returns>
        protected StatusData GetData()
        {
            if (this.InvokeRequired)
                return (StatusData)this.Invoke(new Func<StatusData>(this.GetData));
            else
            {
                StatusData data = new StatusData();
                data.MainText = this._MainText.Text;
                data.MainTextTooltip = this._MainText.ToolTipText;
                data.ProgressCaptionVisible = this._ProgressCaption.Visible;
                data.ProgressCaptionText = this._ProgressCaption.Text;
                data.ProgressBarVisible = this._ProgressBar.Visible;
                data.ProgressBarRatio = GetRatio(this._ProgressBar.Value, this._ProgressBar.Minimum, this._ProgressBar.Maximum);
                data.ProgressCountVisible = this._ProgressCount.Visible;
                data.ProgressCountText = this._ProgressCount.Text;
                data.ProgressErrorVisible = this._ProgressError.Visible;
                data.ProgressErrorText = this._ProgressError.Text;
                return data;
            }
        }
		/// <summary>
		/// Převezme a zobrazí datový objekt, který popisuje obsah status baru.
		/// Zvládá asynchronní přístup.
		/// </summary>
		/// <param name="data"></param>
        protected void SetData(StatusData data)
        {
            if (this.InvokeRequired)
                this.BeginInvoke(new Action<StatusData>(this.SetData), data);
            else
            {
                bool pv1 = (this._ProgressCaption.Visible || this._ProgressBar.Visible || this._ProgressCount.Visible || this._ProgressError.Visible);

                if (data.MainText != null)
                    this._MainText.Text = data.MainText;
                if (data.MainTextTooltip != null)
                    this._MainText.ToolTipText = data.MainTextTooltip;
                if (data.ProgressCaptionVisible.HasValue)
                    this._ProgressCaption.Visible = data.ProgressCaptionVisible.Value;
                if (data.ProgressCaptionText != null)
                    this._ProgressCaption.Text = data.ProgressCaptionText;
                if (data.ProgressBarVisible.HasValue)
                    this._ProgressBar.Visible = data.ProgressBarVisible.Value;
                if (data.ProgressBarRatio.HasValue)
                    this._ProgressBar.Value = GetValue(data.ProgressBarRatio.Value, this._ProgressBar.Minimum, this._ProgressBar.Maximum);
                if (data.ProgressCountVisible.HasValue)
                    this._ProgressCount.Visible = data.ProgressCountVisible.Value;
                if (data.ProgressCountText != null)
                    this._ProgressCount.Text = data.ProgressCountText;
                if (data.ProgressErrorVisible.HasValue)
                    this._ProgressError.Visible = data.ProgressErrorVisible.Value;
                if (data.ProgressErrorText != null)
                    this._ProgressError.Text = data.ProgressErrorText;

                bool pv2 = (this._ProgressCaption.Visible || this._ProgressBar.Visible || this._ProgressCount.Visible || this._ProgressError.Visible);
                if (pv1 != pv2)
                {   // Nedokonalost status baru, vlastnost Spring - workaround:
                    this._MainText.Spring = false;
                    this._MainText.Spring = true;
                }
            }
        }
        /// <summary>
        /// Z dat ProgressBaru (int Value, int Minimum, int Maximum) vypočte Ratio (float 0 ÷ 1).
        /// </summary>
        /// <param name="value"></param>
        /// <param name="minimum"></param>
        /// <param name="maximum"></param>
        /// <returns></returns>
        private float GetRatio(int value, int minimum, int maximum)
        {
            float size = (float)(maximum - minimum);
            if (size <= 0f) return 0f;
            float dist = (float)(value - minimum);
            float ratio = dist / size;
            return (ratio < 0f ? 0f : (ratio > 1f ? 1f : ratio));
        }
        /// <summary>
        /// Z hodnoty ratio (float 0 ÷ 1) a z dat ProgressBaru (int Minimum, int Maximum) vypočte int Value (Minimum ÷ Maximum).
        /// </summary>
        /// <param name="ratio"></param>
        /// <param name="minimum"></param>
        /// <param name="maximum"></param>
        /// <returns></returns>
        private int GetValue(float ratio, int minimum, int maximum)
        {
            float size = (float)(maximum - minimum);
            if (size <= 0f) return minimum;
            float dist = (ratio * size);
            int value = minimum + ((int)Math.Round(dist, 0));
            return (value < minimum ? minimum : (value > maximum ? maximum : value));
        }
        #endregion
    }
	#region Data status baru
    /// <summary>
    /// Data do/z status baru.
    /// Default hodnota každé datové property je null, což při setování má význam "Nesetovat odpovídající property".
    /// </summary>
	public class StatusData
    {
		/// <summary>
		/// Data do/z status baru. Konstruktor.
		/// </summary>
		public StatusData()
		{
			this.InnerProgressData = new ProgressData();
		}
		/// <summary>
		/// Data do/z status baru. Konstruktor.
		/// </summary>
		/// <param name="progressData"></param>
		public StatusData(ProgressData progressData)
		{
			if (progressData != null)
				this.InnerProgressData = progressData;
			else
				this.InnerProgressData = new ProgressData();
		}
		/// <summary>
		/// Balík s daty pro progress bar.
		/// </summary>
		protected ProgressData InnerProgressData { get; set; }
		/// <summary>Text prvku Main = hlavní text ve StatusBaru.  Null hodnota (default) = neměnit aktuální stav</summary>
		public string MainText { get; set; }
		/// <summary>Tooltip k prvku Main = hlavní text ve StatusBaru.  Null hodnota (default) = neměnit aktuální stav</summary>
		public string MainTextTooltip { get; set; }
		/// <summary>Má být viditelný text Caption = před progress barem?  Null hodnota (default) = neměnit aktuální stav</summary>
		public bool? ProgressCaptionVisible { get { return this.InnerProgressData.ProgressCaptionVisible; } set { this.InnerProgressData.ProgressCaptionVisible = value; } }
		/// <summary>Text do políčka Caption.  Null hodnota (default) = neměnit aktuální stav</summary>
		public string ProgressCaptionText { get { return this.InnerProgressData.ProgressCaptionText; } set { this.InnerProgressData.ProgressCaptionText = value; } }
		/// <summary>Má být viditelný Progress bar?  Null hodnota (default) = neměnit aktuální stav</summary>
		public bool? ProgressBarVisible { get { return this.InnerProgressData.ProgressBarVisible; } set { this.InnerProgressData.ProgressBarVisible = value; } }
		/// <summary>Hodnota do ProgressBaru, v rozmezí 0 až 1.  Null hodnota (default) = neměnit aktuální stav</summary>
		public float? ProgressBarRatio { get { return this.InnerProgressData.ProgressBarRatio; } set { this.InnerProgressData.ProgressBarRatio = value; } }
		/// <summary>Má být viditelný text Count = za progress barem? Text je určen pro zobrazení počtu.  Null hodnota (default) = neměnit aktuální stav</summary>
		public bool? ProgressCountVisible { get { return this.InnerProgressData.ProgressCountVisible; } set { this.InnerProgressData.ProgressCountVisible = value; } }
		/// <summary>Text do políčka Count. Text je určen pro zobrazení počtu.  Null hodnota (default) = neměnit aktuální stav</summary>
		public string ProgressCountText { get { return this.InnerProgressData.ProgressCountText; } set { this.InnerProgressData.ProgressCountText = value; } }
		/// <summary>Má být viditelný text Error = za textem Count? Text je určen pro zobrazení chyb.  Null hodnota (default) = neměnit aktuální stav</summary>
		public bool? ProgressErrorVisible { get { return this.InnerProgressData.ProgressErrorVisible; } set { this.InnerProgressData.ProgressErrorVisible = value; } }
		/// <summary>Text do políčka Error. Text je určen pro zobrazení chyb.  Null hodnota (default) = neměnit aktuální stav</summary>
		public string ProgressErrorText { get { return this.InnerProgressData.ProgressErrorText; } set { this.InnerProgressData.ProgressErrorText = value; } }
	}
	#endregion
}
